/*! \file WindowImpl.cpp
 *	\brief 
 *
 *	created:	2010/02/14
 *	created:	14:2:2010   13:36
 *	filename: 	c:\src\gag-engine\libs\app\win\WindowImpl.cpp
 *	file path:	c:\src\gag-engine\libs\app\win
 *	file base:	WindowImpl
 *	file ext:	cpp
 *	author:		Vitalii Trubchaninov
 *				venngraydog@gmail.com
 */

#include "app_win/stdafx.h"
#include "app_win/WindowImpl.h"

#include "core/exception.h"
#include "core/StringStream.h"

namespace tt{
namespace app_win{

WindowImpl::WindowImpl(HINSTANCE hInstance)
: m_hInstance(hInstance)
{

}

WindowImpl::~WindowImpl()
{
	DestroyWindow(m_hWnd);
}

HWND WindowImpl::hWnd() const
{
	return m_hWnd;
}

tt::String WindowImpl::getAppClassName() const
{
	return String(TEXT("test")) + TEXT("_ClassName");
}

void WindowImpl::registerClass()
{
	String appClassName = getAppClassName();

	WNDCLASSEX wcex;
	ZeroMemory(&wcex, sizeof(WNDCLASSEX));

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= m_hInstance;
	wcex.hIcon			= NULL;//LoadIcon(m_hInstance, MAKEINTRESOURCE(m_iconResourceId) );
	wcex.hIconSm		= NULL;//LoadIcon(m_hInstance, MAKEINTRESOURCE(m_iconResourceIdSmall) );
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW);
	wcex.lpszClassName	= appClassName.c_str();
	wcex.lpszMenuName	= NULL;

	RegisterClassEx(&wcex);
}

void WindowImpl::createWindow(const app::WindowBounds& bounds)
{
	app::WindowSize actualSize( bounds.size() );

	DWORD ex_style = WS_EX_OVERLAPPEDWINDOW;
	DWORD style = WS_OVERLAPPEDWINDOW;
	if(fullscreen())
	{
		ex_style = 0;
		style = WS_POPUP;
	}
	else
	{
		RECT rect;
		rect.left = bounds.min.x;
		rect.top = bounds.min.y;
		rect.right = bounds.max.x;
		rect.bottom = bounds.max.y;
		bool menuExists = false;// = m_menuResourceId != NULL;
		AdjustWindowRectEx(&rect, style, menuExists, ex_style);
		rect.right -= rect.left;
		rect.bottom -= rect.top;
		actualSize.x = rect.right;
		actualSize.y = rect.bottom;
	}

	String appClassName = getAppClassName();
	String appName = TEXT("test");
	m_hWnd = CreateWindowEx(
		ex_style,
		appClassName.c_str(), 
		appName.c_str(), 
		style,
		bounds.min.x, bounds.min.y, actualSize.x, actualSize.y,
		NULL, NULL, m_hInstance, (LPVOID)this);

	if (!m_hWnd)
		ttThrow( TEXT("SimpleApp::createWindow") );
}

void WindowImpl::onCreate( const app::WindowBounds& bounds )
{
	registerClass();
	createWindow(bounds);
}

void WindowImpl::onShow( app::WindowShowType value )
{
	Int cmdShow = (value == app::WST_SHOW) ? SW_SHOW : SW_HIDE;
	ShowWindow(m_hWnd, cmdShow);
}

bool WindowImpl::onUpdate()
{
#if 0
	static UInt updateCount = 0;
	++updateCount;

	StringStream ss;
	ss << "Update count=" << updateCount;
	SetWindowText(m_hWnd, ss.str().c_str());
#endif //0

	// Main message loop:
	MSG msg;
	if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
	{
		if (!GetMessage(&msg, NULL, 0, 0))
			return false;

		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return true;
}

LPARAM WindowImpl::onWndProc( UINT message, WPARAM wParam, LPARAM lParam )
{
	switch (message)
	{
	case WM_COMMAND:
		{
// 			Int wmId    = LOWORD(wParam);
// 			Int wmEvent = HIWORD(wParam);
			// Parse the menu selections:
#if 0
			switch (wmId)
			{
			case IDM_ABOUT:
				DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
				break;
			case IDM_EXIT:
				DestroyWindow(hWnd);
				break;
			default:
				return DefWindowProc(hWnd, message, wParam, lParam);
			}
#else
			return DefWindowProc(m_hWnd, message, wParam, lParam);
#endif
		}
		break;
	case WM_CHAR:
		{
			int key = (int)wParam;
			if(key == VK_ESCAPE)
				PostQuitMessage(0);
		}
		break;
 	case WM_PAINT:
		{
			PAINTSTRUCT ps;
			::BeginPaint(hWnd(), &ps);
			::EndPaint(hWnd(), &ps);
		}
		return 1;// do not dispatch anymore
	case WM_ERASEBKGND :
		return 1; // do not dispatch anymore
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_CLOSE:
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(m_hWnd, message, wParam, lParam);
	}
	return 0;
}

//////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WindowImpl::WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
	if (message == WM_CREATE)
	{
		LPCREATESTRUCT cs = reinterpret_cast<LPCREATESTRUCT>(lParam);
		SetWindowLongPtr( hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(cs->lpCreateParams) );
	}
	else
	{
		WindowImpl* windowImpl = reinterpret_cast<WindowImpl*>( GetWindowLongPtr(hWnd, GWLP_USERDATA) );
		if (windowImpl)
			return windowImpl->onWndProc(message, wParam, lParam);
	}
	return DefWindowProc( hWnd, message, wParam, lParam );
}

app::WindowBounds WindowImpl::onBounds() const
{
	RECT rect;
	GetWindowRect(m_hWnd, &rect);
	return app::WindowBounds(rect.left, rect.top, rect.right, rect.bottom);
}

} //namespace app_win
} //namespace tt
